/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "hpm6e00.h"
#include "Wed_framework.h"

/*******************************************************************************
 * Macro operate
 ******************************************************************************/
#define NET_RECV_BUF_NUM               6

#define CLAUSE_22_SEGMENT_LEN          0x1F
#define MAX_SEGMENT                    CLAUSE_22_SEGMENT_LEN
#define GPIO_MDIO_CMD_BITS             0x10
#define GPIO_MDIO_WRITE_CMD            0x01
#define GPIO_MDIO_READ_CMD             0x02
#define GPIO_MDIO_ST                   (1 << 14)
#define GPIO_MDIO_SET_TA(ta)           (ta)
#define GPIO_MDIO_SET_OP(op)           ((op) << 12)
#define GPIO_MDIO_SET_PHY_ADDR(addr)   ((addr & MAX_SEGMENT) << 7)
#define GPIO_MDIO_SET_REG_ADDR(addr)   ((addr & MAX_SEGMENT) << 2)

#define MDIO_SET_CMD(op, phy_addr, reg_addr, ta)                              \
    (GPIO_MDIO_ST | GPIO_MDIO_SET_OP(op) | GPIO_MDIO_SET_PHY_ADDR(phy_addr) | \
     GPIO_MDIO_SET_REG_ADDR(reg_addr) | GPIO_MDIO_SET_TA(ta))

/*******************************************************************************
 * Static
 ******************************************************************************/
/* \brief 接收缓存 */
static uint8_t *__g_p_recv_buf;

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief MDIO 写函数
 */
static int __mdio_write(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t data){
    return tsw_ep_mdio_write((int)p_opts_arg, phy_addr, phy_reg, data);
}

/**
 * \brief MDIO 读函数
 */
static int __mdio_read(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t *p_data){
    return tsw_ep_mdio_read((int)p_opts_arg, phy_addr, phy_reg, p_data);
}

/* \brief MII 操作函数集 */
struct Wed_mii_opts __g_mii_opts = {
    .p_fn_mdio_write = __mdio_write,
    .p_fn_mdio_read  = __mdio_read,
};

/**
 * \brief GPIO MDIO 读寄存器函数
 */
static int __mdio_gpio_read_reg(uint32_t phy_addr, uint16_t reg_addr){
    uint16_t data = 0;
    uint16_t cmd  = 0;
    uint8_t i, bit;

    ioc_pad_gpio_output_set(IOC_PAD_PF01);
    ioc_pad_ctrl_set(IOC_PAD_PF01, IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_PE_SET(1));
    ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);

    /* Sending 32bit PRE data */
    for(i = 0; i < 32; i++) {
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }

    /*Send 16 bit volume 22 command*/
    cmd = MDIO_SET_CMD(GPIO_MDIO_READ_CMD, phy_addr, reg_addr, 0x00);
    for (i = 0; i < GPIO_MDIO_CMD_BITS; ++i) {
        bit = (cmd >> ((GPIO_MDIO_CMD_BITS - 1) - i)) & 0x01;
        if (bit) {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);
        }
        else {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 0);
        }
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }

    /*Receive data: Configure MDIO pin as input mode*/
    ioc_pad_gpio_input_set(IOC_PAD_PF01);
    ioc_pad_ctrl_set(IOC_PAD_PF01, IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_PE_SET(1));

    for(i = 0; i < 16; i++) {
        data |= ioc_pad_gpio_sta_get(IOC_PAD_PF01) << (15 - i);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }
    /*Restore the bus to idle*/
    ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);

    return data;
}

/**
 * \brief GPIO MDIO 写寄存器函数
 */
static void __mdio_gpio_write_reg(uint32_t phy_addr,
                                  uint16_t reg_addr,
                                  uint16_t data){
    uint16_t cmd = 0;
    uint8_t i, bit;

    ioc_pad_gpio_output_set(IOC_PAD_PF01);
    ioc_pad_ctrl_set(IOC_PAD_PF01, IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_PE_SET(1));
    ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);

    /*Sending 32bit PRE data*/
    for(i = 0; i < 32; i++) {
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }

    cmd = MDIO_SET_CMD(GPIO_MDIO_WRITE_CMD, phy_addr, reg_addr, 0x02);
    for (i = 0; i < GPIO_MDIO_CMD_BITS; ++i) {
        bit = (cmd >> ((GPIO_MDIO_CMD_BITS - 1) - i)) & 0x01;
        if (bit) {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);
        }
        else {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 0);
        }
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }

    /*Send 16bit data*/
    for(i = 0; i < 16; i++) {
        bit = (data >> (15 - i)) & 0x01;
        if (bit) {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);
        }
        else {
            ioc_pad_gpio_sta_set(IOC_PAD_PF01, 0);
        }
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 1);
        ioc_pad_gpio_sta_set(IOC_PAD_PF00, 0);
    }
    /*Restore the bus to idle*/
    ioc_pad_gpio_sta_set(IOC_PAD_PF01, 1);
}

/**
 * \brief MDIO 写函数
 */
static int __mdio_gpio_write(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t data){
    __mdio_gpio_write_reg(phy_addr, phy_reg, data);

    return 0;
}

/**
 * \brief MDIO 读函数
 */
static int __mdio_gpio_read(void *p_opts_arg, int phy_addr, int phy_reg, uint16_t *p_data){
    *p_data = __mdio_gpio_read_reg(phy_addr, phy_reg);

    return 0;
}

/* \brief MII 操作函数集 */
struct Wed_mii_opts __g_mii_gpio_opts = {
    .p_fn_mdio_write = __mdio_gpio_write,
    .p_fn_mdio_read  = __mdio_gpio_read,
};

/**
 * \brief TSW 初始化
 */
static int __tsw_init(void){
    static int            is_tsw_init = 0;
    struct tsw_dma_config config;

    if (is_tsw_init == 0) {
        /* 配置 RTC 时钟源为 100 MHz */
        HPM_TSW->TSNPORT[0].RTC_CT_TIMER_INCR = 0x0A000000;
        HPM_TSW->TSNPORT[0].RTC_CR |= (1 << 2);

        /* 关闭所有的 MAC 的发送接收 */
        tsw_ep_all_mac_ctrl_disable(tsw_mac_type_emac);

        tsw_cam_clear();
        /* 等待 cam 清除完成 */
        clk_cpu_delay_ms(10);
        /* 使能所有端口 VLAN-ID 1 */
        tsw_cam_vlan_port_set();

        tsw_default_dma_cfg_get(&config);
        /* 初始化接收与发送 */
        tsw_send_init(&config);
        tsw_recv_init(&config);

        /* 设置 MDC 时钟频率为 2.5MHz */
        tsw_ep_mdio_cfg_set(TSW_TSNPORT_PORT1, 19);

        /* 关闭未知帧转发 */
        HPM_TSW->LU_MAIN_NN_ACTION = 0;
        /* 关闭广播帧转发 */
        HPM_TSW->LU_MAIN_BC_ACTION = 0;

        /* 分配 DMA 接收缓存 */
        __g_p_recv_buf = Wed_mem_dma_align_alloc(1536 * NET_RECV_BUF_NUM, 64);
        if (__g_p_recv_buf == NULL) {
            return -WED_ENOMEM;
        }
        memset(__g_p_recv_buf, 0, 1536 * NET_RECV_BUF_NUM);

        /* 提交接收缓存 */
        for (uint8_t i = 0; i < NET_RECV_BUF_NUM; i++) {
            tsw_commit_recv_desc(__g_p_recv_buf + 1536 * i, 1536, i);
        }

        is_tsw_init = 1;
    }
    return 0;
}

/**
 * \brief 网络设备初始化函数
 */
static int __netdev_init(void *p_opts_arg){
    int                ret, port = (int)p_opts_arg;
    int                phy_addr  = 0;
    uint8_t            mac[6]    = {0};
    struct Wed_phy    *p_phy     = NULL;
    uint32_t           gpr_ctrl2 = 0;
    uint32_t           mac_ctrl  = 0;
    uint64_t           mac_temp  = 0;
    struct Wed_phy_cfg cfg;

    ret = __tsw_init();
    if (ret != 0) {
        return ret;
    }

    mac[0] = 0x01;
    mac[1] = 0x00;
    mac[2] = 0x5E;
    mac[3] = 0x00;
    mac[4] = 0x00;

    if (port == TSW_TSNPORT_PORT1) {
        p_phy    = Wed_phy_find_by_name("phy0");
        phy_addr = 1;
        mac[5]   = 0x01;
    } else {
        p_phy    = Wed_phy_find_by_name("phy2");
        phy_addr = 3;
        mac[5]   = 0x02;
    }
    if (p_phy == NULL) {
        return -WED_ENODEV;
    }

    /* 复位 PHY */
    ret = Wed_phy_reset(p_phy, phy_addr, 1000);
    if (ret != 0) {
        return ret;
    }
    /* 检查 PHY 芯片 ID */
    ret = Wed_phy_yt8512h_id_chk(p_phy, phy_addr);
    if (ret != 0) {
        return ret;
    }
    /* PHY 设备下电 */
    ret = Wed_phy_down(p_phy, phy_addr);
    if (ret != 0) {
        return ret;
    }
    /* 设置链接灯 */
    ret = Wed_phy_yt8512h_link_led_set(p_phy, phy_addr, YT8512H_LED0);
    if (ret != 0) {
        return ret;
    }
    /* 设置激活灯 */
    ret = Wed_phy_yt8512h_active_led_set(p_phy, phy_addr, YT8512H_LED1);
    if (ret != 0) {
        return ret;
    }

    ret = Wed_phy_yt8512h_sleep_control(p_phy, phy_addr);
    if (ret != 0) {
        return ret;
    }
    /* 设置工作模式 */
    ret = Wed_phy_work_model_set(p_phy, phy_addr, &cfg);
    if (ret != 0) {
        return ret;
    }
    /* PHY 设备上电 */
    ret = Wed_phy_up(p_phy, phy_addr);
    if (ret != 0) {
        return ret;
    }
    /* 关闭所有的 MAC 的发送接收 */
    tsw_ep_all_mac_ctrl_disable(tsw_mac_type_emac);
    /* 设置 MAC 地址 */
    tsw_ep_mac_addr_set(port, mac, 1);

    mac_ctrl = HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MAC_CTRL;
    mac_ctrl &= ~(TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_MASK | TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_MASK);
    mac_ctrl &= ~TSW_TSNPORT_MAC_MAC_MAC_CTRL_RESSTAT_MASK;
    mac_ctrl |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_CLKSEL_SET(1);
    mac_ctrl |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_PHYSEL_SET(0);
    mac_ctrl |= TSW_TSNPORT_MAC_MAC_MAC_CTRL_GMIIMODE_SET(0);

    gpr_ctrl2 |= TSW_TSNPORT_GPR_CTRL2_PHY_INTF_SEL_SET(tsw_port_phy_itf_rmii);
    gpr_ctrl2 |= TSW_TSNPORT_GPR_CTRL2_RMII_TXCLK_SEL_SET(1);
    gpr_ctrl2 |= TSW_TSNPORT_GPR_CTRL2_PAD_OE_ETH_REFCLK_SET(1);
    gpr_ctrl2 |= TSW_TSNPORT_GPR_CTRL2_MAC_SPEED_SET(3);

    HPM_TSW->TSNPORT[port].MAC[tsw_mac_type_emac].MAC_MAC_CTRL = mac_ctrl;

    tsw_port_clk_delay_set(port, 0, 0);

    HPM_TSW->TSNPORT[port].GPR_CTRL2 = gpr_ctrl2;

    /* 使能所有的 MAC 的发送接收 */
    tsw_ep_all_mac_ctrl_enable(tsw_mac_type_emac);

    mac_temp = (uint64_t)mac[0] | (uint64_t)mac[1]<<8 | (uint64_t)mac[2]<<16 |
               (uint64_t)mac[3]<<24 | (uint64_t)mac[4]<<32 | (uint64_t)mac[5]<<40;

    tsw_lookup_table_set(port, (1<< (port + 1)) | 0x01, mac_temp);

    HPM_TSW->CENTRAL_CSR_CONFIG = 0;

    do {
        clk_cpu_delay_ms(1000);
        /* 等待 PHY 链接上 */
        ret = Wed_phy_yt8512h_status_get(p_phy, phy_addr);
        if (ret != 0) {
            return ret;
        }
    } while (p_phy->is_link_up == 0);

    return 0;
}

/**
 * \brief 网络设备原始输出函数
 */
static int __netdev_raw_output(void *p_opts_arg, uint8_t *p_buf, uint16_t buf_len){
    int      ret;
    int      port     = (int)p_opts_arg;
    uint8_t *p_buf_tx = NULL;

    p_buf_tx = Wed_mem_dma_align_alloc(1536, 64);
    if (p_buf_tx == NULL) {
        return -WED_ENOMEM;
    }
    memset(p_buf_tx, 0, 1536);

    p_buf_tx[0] = port + 1;

    memcpy(p_buf_tx + 16, p_buf, buf_len);

    ret = tsw_frame_send_chk_resp(p_buf_tx, buf_len + 16, 0);

    if (HPM_TSW->MM2S_DMA_SR & (1 << 3)) {
        HPM_TSW->MM2S_DMA_SR = (1 << 3);
    }

    Wed_mem_dma_align_free(p_buf_tx);

    return ret;
}

/* \brief 网络设备操作函数集 */
struct Wed_netdev_opts __g_netdev_opts = {
    .p_fn_init       = __netdev_init,
    .p_fn_raw_output = __netdev_raw_output,
};

static uint8_t  __g_recv_id;
static uint16_t __g_recv_len;
int tsw_data_recv(uint8_t *p_buf_data){
    uint16_t len_ret = __g_recv_len - 16;
    memcpy(p_buf_data, __g_p_recv_buf + __g_recv_id * 1536 + 16, len_ret);

    __g_recv_id  = 0;
    __g_recv_len = 0;
    return len_ret;
//    int ret;
//
//    struct tsw_frame frame = {0};
//
//    ret = tsw_frame_recv(&frame);
//    if (ret == 0) {
//        memcpy(p_buf_data, __g_p_recv_buf, frame.len);
//        return frame.len;
//    }
//    return ret;
}

int tsw_recv_data_len_get(uint16_t *p_len){
    uint32_t resp;
    int      stat = -ETIME;

    if (TSW_S2MM_DMA_SR_IRQ_GET(HPM_TSW->S2MM_DMA_SR)) {
        resp = HPM_TSW->S2MM_RESP;

        __g_recv_id  = TSW_S2MM_RESP_ID_GET(resp);
        __g_recv_len = TSW_S2MM_RESP_LENGTH_GET(resp);
        *p_len = __g_recv_len;

        if (TSW_S2MM_RESP_DECERR_GET(resp) || TSW_S2MM_RESP_SLVERR_GET(resp)) {
            stat = -EPERM;
        } else {
            stat = 0;
        }

        tsw_commit_recv_desc(__g_p_recv_buf + 1536 * __g_recv_id, 1536, __g_recv_id);

        HPM_TSW->S2MM_DMA_SR = TSW_S2MM_DMA_SR_IRQ_MASK;
    }

    return stat;
}

